#pragma once

#include<iostream>
#include<vector>
#include<queue>
#include<functional>
#include<unistd.h>
#include"Log.hpp"
#include"Mutex.hpp"
using namespace LogMod;
using namespace MutexMod;

using task_t = std::function<void()>;
const int defthnum = 5;

namespace Mythreadpool{


    template<typename T>
    class threadpool
    {
    private:
        int _thnum;
        std::vector<pthread_t> _th;
        std::queue<T> _quetask;
        Mutex _mutex;
        pthread_cond_t _cond;
        bool _Isruning;
        int wait_ths;

    private:

        static void* handlework(void* argv)
        {
            //thread_t* self = static_cast<thread_t*>(argv);
            threadpool* tmpthis = static_cast<threadpool*>(argv);
            while(true)
            {
                tmpthis->_mutex.lock();
                while (tmpthis->_Isruning && (tmpthis->_quetask.size() == 0))
                {
                    ++tmpthis->wait_ths;
                    pthread_cond_wait(&tmpthis->_cond,tmpthis->_mutex.getmutex());
                    --tmpthis->wait_ths;
                    //LOG(level::DEBUG)<<"wait_thread:"<<tmpthis->wait_ths;
                    //sleep(1);
                }

                if(!tmpthis->_Isruning && tmpthis->_quetask.size() == 0)
                {
                    tmpthis->_mutex.unlock();
                    break;
                }

                T t = tmpthis->_quetask.front();
                tmpthis->_quetask.pop();

                tmpthis->_mutex.unlock();
                
                //sleep(1);
                t();
            }
            return (void*)0;
        }


    public:
        threadpool()
        :_thnum(defthnum),
        wait_ths(0),
        _Isruning(false)
        {
            pthread_cond_init(&_cond,NULL);
            for(int i = 0;i < _thnum;i++)
            {
                pthread_t th;
                _th.emplace_back(th);
            }
            LOG(level::INFO)<<"Init success";
        }

        void Start()
        {
            _Isruning = true;
            for(auto &e : _th)
            {
                pthread_create(&e,NULL,handlework,this);
            }
        }

        void Enqueue(const T& task)
        {
            if(_Isruning)
            {
                SimpleMutex Mutex(_mutex);
                _quetask.push(task);
                if(wait_ths > 0)
                {
                    pthread_cond_signal(&_cond);
                }
                LOG(level::INFO)<<"enqueue success" ;
            }
            else
                LOG(level::WARING)<<"FORBID INPUT TASK";
        }

        void Stop()
        {
            _Isruning = false;
            pthread_cond_broadcast(&_cond);
            LOG(level::INFO)<<"线程退出 不再处理后来任务";
        }

        void Join()
        {
            for(auto &e : _th)
            {
                pthread_join(e,NULL);
            }
            LOG(level::INFO)<<"线程join退出";
        }

        ~threadpool(){}
    };

    
}
